home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 027a / onotes.zip / TBMANY.PRG < prev    next >
Text File  |  1991-04-19  |  16KB  |  326 lines

  1. *╔══════════════════════════════════════════════════════════════════╗*
  2. *║   Module Name:   TBSIMPLE.PRG                                    ║*
  3. *║   Description:   A bare bones 'one to many' TBrowse system.      ║*
  4. *║   Notes......:   COMPILE with the /n/w switch.                   ║*
  5. *║   Author.....:   Micheal Todd Charron                            ║*
  6. *║   Date.......:   April 29, 1991                                  ║*
  7. *║   History....:   Lee Dimambro asked me to write a bare bones     ║*
  8. *║                  'one to many' TBrowse system from scratch.  30  ║*
  9. *║                  minutes from start to finish.  It could have    ║*
  10. *║                  been faster if I hadn't been using WP 5.1 as    ║*
  11. *║                  the program editor.  This program is similiar   ║*
  12. *║                  but with less frills.  Thanks Lee.              ║*
  13. *║                                                                  ║*
  14. *║   Copyright..:   (c) The people at Nantucket Canada, 1991        ║*
  15. *╚══════════════════════════════════════════════════════════════════╝*
  16. #include "inkey.ch"
  17.  
  18. FUNCTION Main()
  19.         LOCAL nI, nKey
  20.         LOCAL oBrowse := TBROWSEDB( 1, 2, 22, 78 )
  21.  
  22.         USE MANY INDEX MANY NEW
  23.         USE ONE NEW
  24.         SET RELATION TO ONE->Group INTO MANY
  25.  
  26.         CLS
  27.  
  28.         @0, 1 TO 23, 79 DOUBLE
  29.         oBrowse:HEADSEP := '═╤═'
  30.         oBrowse:COLSEP  := ' │ '
  31.  
  32.         FOR nI := 1 TO FCOUNT()
  33.                 oBrowse:ADDCOLUMN( TBCOLUMNNEW( FIELD( nI ),;
  34.                         FIELDBLOCK( FIELD( nI ) ) ) )
  35.         NEXT nI
  36.  
  37.         DO WHILE .T.
  38.                 DO WHILE ! ( oBrowse:STABILIZE() )
  39.                 ENDDO
  40.  
  41.                 nKey := INKEY( 0 )
  42.  
  43.                 DO CASE
  44.                 CASE nKey == K_ENTER
  45.                         MANY->( ManyBrowse( ONE->Group ) )                        
  46.                 CASE nKey == K_DOWN
  47.                         oBrowse:DOWN()
  48.                 CASE nKey == K_UP
  49.                         oBrowse:UP()
  50.                 CASE nKey == K_PGDN
  51.                         oBrowse:PAGEDOWN()
  52.                 CASE nKey == K_PGUP
  53.                         oBrowse:PAGEUP()
  54.                 CASE nKey == K_RIGHT
  55.                         oBrowse:RIGHT()
  56.                 CASE nKey == K_LEFT
  57.                         oBrowse:LEFT()
  58.                 CASE nKey == K_ESC
  59.                         EXIT
  60.                 ENDCASE
  61.  
  62.         ENDDO
  63.  
  64. RETURN Nil
  65.  
  66.  
  67. * * * *
  68. *
  69. *        Function ManyBrowse()
  70. *
  71. FUNCTION ManyBrowse( xKey )
  72.         LOCAL nI, nKey
  73.         LOCAL oBrowse := TBROWSENEW( 9, 40, 21, 77 )
  74.  
  75.         SAVE SCREEN
  76.  
  77.         @8, 39 TO 22, 78 DOUBLE
  78.         oBrowse:HEADSEP := '═╤═'
  79.         oBrowse:COLSEP  := ' │ '
  80.  
  81.         oBrowse:SKIPBLOCK :=;
  82.                 { | nMove | SkipKey( nMove, xKey ) }
  83.  
  84.         FOR nI := 1 TO FCOUNT()
  85.                 oBrowse:ADDCOLUMN( TBCOLUMNNEW( FIELD( nI ),;
  86.                         FIELDBLOCK( FIELD( nI ) ) ) )
  87.         NEXT nI
  88.  
  89.         DO WHILE .T.
  90.                 DO WHILE ! ( oBrowse:STABILIZE() )
  91.                 ENDDO
  92.  
  93.                 nKey := INKEY( 0 )
  94.  
  95.                 DO CASE
  96.                 CASE nKey == K_DOWN
  97.                         oBrowse:DOWN()
  98.                 CASE nKey == K_UP
  99.                         oBrowse:UP()
  100.                 CASE nKey == K_PGDN
  101.                         oBrowse:PAGEDOWN()
  102.                 CASE nKey == K_PGUP
  103.                         oBrowse:PAGEUP()
  104.                 CASE nKey == K_RIGHT
  105.                         oBrowse:RIGHT()
  106.                 CASE nKey == K_LEFT
  107.                         oBrowse:LEFT()
  108.                 CASE nKey == K_ESC
  109.                         EXIT
  110.                 ENDCASE
  111.  
  112.         ENDDO
  113.  
  114.         RESTORE SCREEN
  115.  
  116. RETURN Nil
  117.  
  118.  
  119.  
  120. * * * *
  121. *
  122. *        Function SkipKey()
  123. *
  124. FUNCTION SkipKey( nMove, xKey )
  125.         LOCAL nI, nMovement := 0
  126.  
  127.         IF nMove > 0
  128.                 FOR nI := 1 TO nMove
  129.                         SKIP 1
  130.                         IF xKey != UPPER( MANY->Group )
  131.                                 SKIP -1
  132.                                 EXIT
  133.                         ENDIF
  134.                         nMovement++
  135.                 NEXT nI
  136.         ELSEIF nMove < 0
  137.                 FOR nI := 1 TO -( nMove )
  138.                         SKIP -1
  139.                         IF xKey != UPPER( MANY->Group ) .OR. BOF()
  140.                                 IF ! BOF()
  141.                                         SKIP 1
  142.                                 ENDIF
  143.                                 EXIT
  144.                         ENDIF
  145.                         nMovement--
  146.                 NEXT nI
  147.         ENDIF
  148.  
  149. RETURN nMovement
  150.  
  151.  
  152. /*****************************************************************************
  153.   FUNCTION Main()
  154. ******************************************************************************
  155. I will assume that you have already looked through TBSIMPLE.PRG and do not
  156. need an explanation of simpler aspects of the TBrowse.
  157.  
  158.         ╒════════════════════════════════════════════════════════════════════╕
  159. Line 22 │  USE MANY INDEX MANY NEW                                           │
  160. Line 23 │  USE ONE NEW                                                       │
  161. Line 24 │  SET RELATION TO ONE->Group INTO MANY                              │
  162.         ╘════════════════════════════════════════════════════════════════════╛
  163. Opens the 'MANY' database which holds multiple records for every record in
  164. the 'ONE' database.  Also on the same line the 'MANY' index is opened.  This
  165. index has the key of UPPER( GROUP ).  Then the 'ONE' database is opened which
  166. then becomes the active database.  Take note that the 'NEW' clause in the
  167. 'USE' command will automatically selects the next available workarea.  Then,
  168. finally, the relation from the 'ONE' database into the 'MANY' database is set.
  169.  
  170.         ╒════════════════════════════════════════════════════════════════════╕
  171. Line 29 │  @0, 1 TO 23, 79 DOUBLE                                            │
  172. Line 30 │  oBrowse:HEADSEP := '═╤═'                                          │
  173. Line 31 │  oBrowse:COLSEP  := ' │ '                                          │
  174.         ╘════════════════════════════════════════════════════════════════════╛
  175. Fluff, pure fluff.  I take the luxury of adding a double line box around the
  176. main TBrowse and providing heading and column separators for the TBrowse.
  177.  
  178.         ╒════════════════════════════════════════════════════════════════════╕
  179. Line 44 │  CASE nKey == K_ENTER                                              │
  180. Line 45 │          MANY->( ManyBrowse( ONE->Group ) )                        │
  181.         ╘════════════════════════════════════════════════════════════════════╛
  182. Calls ManyBrowse() and passes the current value of the relation's key
  183. expression.
  184.  
  185. 'MANY->( )' is a neat trick which will automatically make the 'MANY' workarea
  186. the current workarea when the function between the paranthesis is executed.
  187. But the really great aspect of this is that you are automatically returned to
  188. the workarea that was active before the function call.  Even if you select
  189. other workareas in the function you call, you are returned to the workarea
  190. that was active before the function call.  Use it, its helpful.
  191.  
  192.  
  193. ******************************************************************************
  194.   FUNCTION ManyBrowse()
  195. ******************************************************************************
  196.         ╒════════════════════════════════════════════════════════════════════╕
  197. Line 73 │  LOCAL oBrowse := TBROWSENEW( 9, 40, 21, 77 )                      │
  198.         ╘════════════════════════════════════════════════════════════════════╛
  199. The 'MANY' TBrowse object is created and it's reference is assigned to the
  200. variable "oBrowse".  The variable "oBrowse" in this function and the variable
  201. "oBrowse" in the Main() function are not the same variable, remember that.  By
  202. declaring them LOCAL they only share the same name.  They are only visible to
  203. the functions that they are declared in.
  204.  
  205. In Clipper 5.0 there are two ways to create a TBrowse object.  The first way
  206. is to use the function TBROWSEDB() and the second way is to use the function
  207. TBROWSENEW().  TBROWSEDB() creates the TBrowse object with a predefined
  208. mechanism for moving from the top to the bottom of a database.  The mechanism
  209. is stored in object in the instance variable 'SKIPBLOCK'.  With TBROWSENEW(),
  210. the object is created without a mechanism.  The instance variable 'SKIPBLOCK'
  211. is empty.
  212.  
  213. For the 'MANY' TBrowse the mechanism for moving through the database must be
  214. defined in order to assure that the TBrowse will only display the data that
  215. corresponds to the related record in the 'ONE' TBrowse.
  216.  
  217.         ╒════════════════════════════════════════════════════════════════════╕
  218. Line 75 │  SAVE SCREEN                                                       │
  219.         ╘════════════════════════════════════════════════════════════════════╛
  220. The screen is saved so that the main TBrowse screen can be returned to without
  221. disturbing its contents.
  222.  
  223.         ╒════════════════════════════════════════════════════════════════════╕
  224. Line 81 │  oBrowse:SKIPBLOCK :=;                                             │
  225. Line 82 │          { | nMove | SkipKey( nMove, xKey ) }                      │
  226.         ╘════════════════════════════════════════════════════════════════════╛
  227. The mechanism for moving through the 'MANY' database is created and stored in
  228. the instance variable SKIPBLOCK.  When the TBrowse starts to display the data
  229. it will evaluate this code block which is stored in its SKIPBLOCK instance
  230. variable.
  231.  
  232. Please remember that nothing is being executed at this point.  The code block
  233. is only being stored for later use.
  234.  
  235.         ╒════════════════════════════════════════════════════════════════════╕
  236. Line 90 │  DO WHILE ! ( oBrowse:STABILIZE() )                                │
  237. Line 91 │  ENDDO                                                             │
  238.         ╘════════════════════════════════════════════════════════════════════╛
  239. When this loop is encountered, it will check for any data rows that have been
  240. changed and loop through until they are updated.  If the TBrowse must find
  241. data that it has not already found, it will evaluate the code block stored in
  242. the instance variable SKIPBLOCK and pass into the code block the number of
  243. rows it must move to display that data.
  244.  
  245.          ╒═══════════════════════════════════════════════════════════════════╕
  246. Line 108 │  CASE nKey == K_ESC                                               │
  247. Line 109 │          EXIT                                                     │
  248.          ╘═══════════════════════════════════════════════════════════════════╛
  249. Exits out of the DO WHILE loop and returns to the main TBrowse.
  250.  
  251.          ╒═══════════════════════════════════════════════════════════════════╕
  252. Line 114 │  RESTORE SCREEN                                                   │
  253.          ╘═══════════════════════════════════════════════════════════════════╛
  254. Restores the main TBrowse screen.
  255.  
  256.  
  257. ******************************************************************************
  258.   FUNCTION SkipKey()
  259. ******************************************************************************
  260.          ╒═══════════════════════════════════════════════════════════════════╕
  261. Line 124 │  FUNCTION SkipKey( nMove, xKey )                                  │
  262.          ╘═══════════════════════════════════════════════════════════════════╛
  263. The variable "nMove" contains the number of rows the TBrowse has requested to
  264. move.  The variable "xKey" contains the value of the key field in the 'ONE'
  265. database.
  266.  
  267.          ╒═══════════════════════════════════════════════════════════════════╕
  268. Line 125 │  LOCAL nI, nMovement := 0                                         │
  269.          ╘═══════════════════════════════════════════════════════════════════╛
  270. The variable "nI" is for the FOR ... NEXT loop and the "nMovement" variable 
  271. will hold the value that the SkipKey() function will return.
  272.  
  273.          ╒═══════════════════════════════════════════════════════════════════╕
  274. Line 127 │  IF nMove > 0                                                     │
  275. Line 128 │          FOR nI := 1 TO nMove                                     │
  276. Line 129 │                  SKIP 1                                           │
  277. Line 130 │                  IF xKey != UPPER( MANY->Group )                  │
  278. Line 131 │                          SKIP -1                                  │
  279. Line 132 │                          EXIT                                     │
  280. Line 133 │                  ENDIF                                            │
  281. Line 134 │                  nMovement++                                      │
  282. Line 135 │          NEXT nI                                                  │
  283.          ╘═══════════════════════════════════════════════════════════════════╛
  284. If the TBrowse has requested to move down more than one row, this code is
  285. executed.  The FOR...NEXT loops from 1 to the value of "nMove" or until the
  286. EXIT command is issued. 
  287.  
  288. On line 129 we SKIP to the next record.
  289.  
  290. On line 130 we check to see if UPPER( MANY->Group ) is different from the
  291. value of xkey.
  292.  
  293. If the value of UPPER( MANY->Group ) is different from the value of xkey, we
  294. have gone too far and must move back one record and exit the FOR...NEXT loop.
  295. Lines 131 and 132 respectively.
  296.  
  297. On line 134 the variable "nMovement" is incremented by one.  Therefore, 
  298. nMovement is incremented by one for every successful loop of the FOR...NEXT
  299. loop.
  300.          ╒═══════════════════════════════════════════════════════════════════╕
  301. Line 137 │  ELSEIF nMove < 0                                                 │
  302. Line 138 │          FOR nI := 1 TO -( nMove )                                │
  303. Line 139 │                  SKIP -1                                          │
  304. Line 140 │                  IF xKey != UPPER( MANY->Group ) .OR. BOF()       │
  305. Line 141 │                          IF ! BOF()                               │
  306. Line 142 │                                  SKIP 1                           │
  307. Line 143 │                          ENDIF                                    │
  308. Line 144 │                          EXIT                                     │
  309. Line 145 │                  ENDIF                                            │
  310. Line 146 │                  nMovement--                                      │
  311. Line 147 │          NEXT nI                                                  │
  312.          ╘═══════════════════════════════════════════════════════════════════╛
  313. This section is much like the previous section.  The only difference is that
  314. the section checks for backward movement through the database and that it also
  315. checks to see if while skipping backwards, the beginning of the file is hit.
  316.  
  317.          ╒═══════════════════════════════════════════════════════════════════╕
  318. Line 149 │  RETURN nMovement                                                 │
  319.          ╘═══════════════════════════════════════════════════════════════════╛
  320. Returns the amount of rows the TBrowse can move.
  321.  
  322. ******************************************************************************/
  323. **    Please remember that this is not the only way to make one of these     **
  324. **    applications.  It is only the simplest way I can think of showing      **
  325. **    how this can be done.                                                  **
  326. *******************************************************************************